using System;
using System.Linq;
using CommonBehaviors.Actions;
using FarmerJoe.Helpers;
using FarmerJoe.Helpers.Logging;
using FarmerJoe.Helpers.Units;
using FarmerJoe.Settings;
using Styx;
using Styx.CommonBot;
using Styx.TreeSharp;
using Styx.WoWInternals;
using Styx.WoWInternals.WoWObjects;
using Action = Styx.TreeSharp.Action;

namespace FarmerJoe.Classes
{
    public static partial class Warlock
    {
        static double BackdraftStacks
        {
            get
            {
                var c = MyAura(StyxWoW.Me, "Backdraft");
                return c == null ? 0 : c.StackCount;
            }
        }

        private static WoWAura MyAura(WoWUnit Who, String What)
        {
            return Who.GetAllAuras().FirstOrDefault(p => p.CreatorGuid == StyxWoW.Me.Guid && p.Name == What);
        }

        // Returns TRUE if is OK for you to cast a spell now
        private static bool IsCastingOK
        {
            get
            {
                //bool result = false;
                if (SpellManager.GlobalCooldown) return false;

                if (Me.IsCasting && (Me.CastingSpell.Name == "Malefic Grasp" || Me.CastingSpell.Name == "Drain Life"))
                {
                    uint latency = (StyxWoW.WoWClient.Latency * 2) + 50;
                    double channelTimeLeft = StyxWoW.Me.CurrentChannelTimeLeft.TotalMilliseconds;

                    if (channelTimeLeft <= latency)
                    {
                        //Log.Write("clipping cast, channel time: " + channelTimeLeft + " latency: " + latency);
                        return true;
                    }
                    //Log.Write("latency " + latency);
                    //Log.Write("channelTimeLeft " + channelTimeLeft);
                    //Log.Write(Colours.InformativeColour, "cast time remaining is " + Me.CurrentCastTimeLeft.TotalSeconds);
                    //Log.Write(Colours.InformativeColour,"channel time remaining is " + Me.CurrentChannelTimeLeft.TotalSeconds);


                }
                return !Me.IsCasting && !Me.IsChanneling;
            }
        }

        private static bool EmberCountOK(string clcSetting)
        {
            return (Me.GetCurrentPower(WoWPowerType.BurningEmbers) >= Convert.ToInt32(clcSetting)*10);
        }

        public static Composite CombatBehavior_Destruction
        {
            get
            {
                return new PrioritySelector(

                    Spells.WaitForCast(),
                    Misc.EnsureTarget(),

                    SummonPet(),
                    PetSpells(),

                    AllFormsHeal(),
                    //new Common.NeedToUseLifeSpirit(new Common.UseLifeSpirit()),
                    Common.UseHealthManaRegenAgent(ClassParser.HealthPotion, ClassParser.ManaPotion),

                    Inventory.UseTrinket1(),
                    Inventory.UseTrinket2(),

                    Movement.MoveToLOS(),
                    Movement.FaceTarget(),
                    Movement.ForceFacingTarget(),
                    Pets.DefendMe(),
                    Movement.Fixes(),

                    // Somehow we've got a target that is not hostile or attackable. Blacklist it and move on
                    new Decorator(ret => !CT.Attackable || CT.IsFriendly,
                        new Sequence(
                            new Action(context => Log.Write(Colours.InformativeColour, "Somehow we've got a target that is friendly or not attackable, blacklisting it and moving on.")),
                            new Action(context => Blacklist.Add(CT, TimeSpan.FromMinutes(1))),
                            new Action(context => Me.ClearTarget())
                        )),
                    
                    
                    // Today is a good day to die!
                    // This. Is. SPARTA!
                    Spells.Cast("Mortal Coil", ret => Me.HealthPercent <= FpswareSettings.Instance.Warlock.MortalCoilHealth),

                    new Decorator(ret => !FpswareSettings.Instance.Warlock.DestructionTwilightWard.Contains("never") && Me.GotTarget && CT.IsCasting && CT.CastingSpell.CastTime > 1000 && CT.CurrentTarget.Guid == Me.Guid,
                            new PrioritySelector(
                                Spells.Cast("Twilight Ward", ret => CT.CastingSpell.School == WoWSpellSchool.Shadow || CT.CastingSpell.School == WoWSpellSchool.Holy)
                                )),

                    new Decorator(ret => !FpswareSettings.Instance.Warlock.DestructionSacrificialPact.Contains("never") && CLC.ResultOK(FpswareSettings.Instance.Warlock.DestructionSacrificialPactWhen) && Me.GotAlivePet,
                        new PrioritySelector(
                            Spells.Cast("Sacrificial Pact", ret => Me.HealthPercent <= FpswareSettings.Instance.Warlock.DestructionSacrificialPactHealth && Me.Pet.HealthPercent >= FpswareSettings.Instance.Warlock.DestructionSacrificialPactMinPetHealth)
                            )),

                    //Spells.Cast("Grimoire of Service", ret => CLC.ResultOK(FpswareSettings.Instance.Warlock.DestructionGrimoireOfService) && SpellManager.HasSpell("Grimoire of Service")),
                    Spells.Cast("Grimoire: " + FpswareSettings.Instance.Warlock.DestructionGrimoirePet, ret => CLC.ResultOK(FpswareSettings.Instance.Warlock.DestructionGrimoireOfService)),
                    Spells.Cast("Shadowburn", ret => !FpswareSettings.Instance.Warlock.Shadowburn.Contains("never") && CT.HealthPercent <= 20 && Me.GetCurrentPower(WoWPowerType.BurningEmbers) >= 10),
                    Spells.Cast("Dark Soul", ret => CLC.ResultOK(FpswareSettings.Instance.Warlock.DestructionDarkSoul) && !WoWSpell.FromId(113858).Cooldown && !Me.HasAura("Dark Soul: Instability")),
                    Spells.Cast("Grimoire of Sacrifice", ret => CLC.ResultOK(FpswareSettings.Instance.Warlock.DestructionGrimoireOfSacrifice) && Me.GotAlivePet && !Me.HasAura("Grimoire of Sacrifice")),
                    Spells.Cast("Curse of the Elements", ret => !FpswareSettings.Instance.Warlock.CurseOfTheElements.Contains("never") && !CT.HasAura("Aura of the Elements") && (CT.AuraTimeLeft("Curse of the Elements") < 3) && IsCastingOK && Timers.AutoExpire("CotE", 3000)),

                    // As its not a channeled spell we'll only try this once every 10 seconds from when it was last cast succesesfully
                    Spells.CastOnGround("Rain of Fire", ret => CT.Location, ret => CLC.CountOfMobs(FpswareSettings.Instance.Warlock.DestructionRainOfFire, 8) && IsCastingOK && Timers.SpellOkToCast("Rain of Fire",10000)),

                    new Decorator(ret => !FpswareSettings.Instance.Warlock.FireAndBrimstone.Contains("never") && CLC.ResultOK(FpswareSettings.Instance.Warlock.FireAndBrimstoneWhen) && EmberCountOK(FpswareSettings.Instance.Warlock.FireAndBrimstoneBurningEmberCount) && CT.HostileUnitsNearTarget(15f).Count() >= 2 && IsCastingOK,
                        new PrioritySelector( Spells.Cast("Fire and Brimstone"))),

                    Spells.Cast("Havoc", ret => FpswareSettings.Instance.Warlock.DestructionHavoc.Contains("always") && AddsAndOthers.HasAdds, ret => Me.AggroUnitsNearTarget(40, true).FirstOrDefault()),
                    

                    // 10 embers is a FULL Burning Ember, 20 embers are 2 FULL burning embers
                    Spells.Cast("Chaos Bolt", ret => EmberCountOK(FpswareSettings.Instance.Warlock.ChaosBolt) && CT.HealthPercent> 45 && IsCastingOK && Timers.SpellOkToCast("Chaos Bolt", 3500)),

                    //[SpellManager] Immolate (348) overrides Corruption (172)
                    Spells.Buff("Corruption", ret => Me.CurrentTarget, ret => !FpswareSettings.Instance.Warlock.Immolate.Contains("never") && CT.AuraTimeLeft("Immolate") < 3 && IsCastingOK && Timers.SpellOkToCast("Immolate", 2700), true),

                    // Lower priority than some DoTs so we can at least kill the target slowly instead of just healing the pet and hoping it will kill the target for us
                    Spells.Cast("Health Funnel", ret => !Spells.HasSpell(108415) && Me.GotAlivePet && Me.Pet.HealthPercent < FpswareSettings.Instance.Warlock.DestructionHealthFunnel && Me.Pet.Distance < 45 && SpellManager.HasSpell("Health Funnel") && !SpellManager.Spells["Health Funnel"].Cooldown),
                    new Decorator(ret => FpswareSettings.Instance.Warlock.DestructionSoulLink.Contains("always") && WoWSpell.FromId(108415).CanCast && Me.GotAlivePet && !Me.Auras.ContainsKey("Soul Link"),
                        new Action(r => Spells.Cast("Soul Link"))),

                    new Decorator(ret => !FpswareSettings.Instance.Warlock.Incinerate.Contains("never") && IsCastingOK,
                        new PrioritySelector(
                            Spells.Cast("Conflagrate", ret => BackdraftStacks <= 0 && Timers.SpellOkToCast("Conflagrate", 2000)),
                    
                            // [SpellManager] Incinerate (29722) overrides Shadow Bolt (686)
                            Spells.Cast("Shadow Bolt")
                            )),

                    

                    Spells.Cast("Fel Flame", ret=> CLC.ResultOK(FpswareSettings.Instance.Warlock.DestructionFelFlame) && IsCastingOK),

                    new Decorator(ret => Me.IsCasting || Me.IsChanneling, new Action(context => RunStatus.Success)),
                    Movement.MoveToTarget(true, 36f)
                    );
            }
        }

        public static Composite PullBehavior_Destruction
        {
            get
            {
                return new PrioritySelector(

                    Spells.WaitForCast(),
                    Misc.EnsureTarget(),
                    new Decorator(ret => Me.Mounted, new Action(context => Mount.Dismount())),
                    Movement.FaceTarget(),
                    Movement.ForceFacingTarget(),
                    Movement.MoveToLOS(),
                    Movement.Fixes(),

                    // Somehow we've got a target that is not hostile or attackable. Blacklist it and move on
                    new Decorator(ret => !CT.Attackable || CT.IsFriendly,
                        new Sequence(
                            new Action(context => Log.Write(Colours.InformativeColour, "Somehow we've got a target that is friendly or not attackable, blacklisting it and moving on.")),
                            new Action(context => Blacklist.Add(CT, TimeSpan.FromMinutes(1))),
                            new Action(context => Me.ClearTarget())
                        )),

                    new Decorator(ret=> Me.GotAlivePet && (!Me.Pet.PetInCombat && !Me.Pet.GotTarget), 
                        new PrioritySelector(
                            new Action(delegate { Pets.CastPetAction("Attack"); }),
                            new ActionAlwaysFail()
                            )),

                    // User defined pull options
                    new Decorator(ret => FpswareSettings.Instance.Warlock.DestructionPull.Contains("user defined"),
                                  new PrioritySelector(

                                      Spells.Cast("Chaos Bolt", ret => EmberCountOK(FpswareSettings.Instance.Warlock.ChaosBolt) && CT.HealthPercent > 45 && IsCastingOK),
                                      Spells.Cast("Corruption", ret=> !Me.IsMoving && Timers.SpellOkToCast("Immolate",2000))
                                      
                                      )),


                    // Automatic fall through stuff
                    new Decorator(ret => FpswareSettings.Instance.Warlock.DestructionPull.Contains("automatic"),
                                  new PrioritySelector(

                                      Spells.Cast("Chaos Bolt", ret => EmberCountOK(FpswareSettings.Instance.Warlock.ChaosBolt) && CT.HealthPercent > 45 && IsCastingOK),
                                      Spells.Cast("Corruption", ret => !Me.IsMoving && Timers.SpellOkToCast("Immolate", 2000))


                                      )),


                    new Decorator(ret => Me.IsCasting || Me.IsChanneling, new Action(context => RunStatus.Success)),

                    Movement.PullApproach(),
                    Movement.MoveToTarget(true, 36f)
                    );
            }
        }
        
    }
}